<script setup>
import {ref,unref,toValue, useSlots, onMounted, onUnmounted, watch, nextTick, reactive, getCurrentInstance,toRaw} from 'vue'
import {util, ajax,ExcelExporter} from 'framework'
import {message,heyuiConfig,modal,confirm} from 'heyui'
import {useI18n,$t} from "i18n";

const showSearch = ref(true)
const slots = useSlots()
const tableRef = ref(null)
const ds = ref({}), dtRef = ref(null)
const canExport=ref(false)
const {t}=useI18n({
  zh:{
    "DataExport":"数据导出",
    "ExportTitle":"导出行/页",
    "Select All Columns":"选择所有列",
    "from the current":"当前起第",
    "pages":"页",
  },
  en:{
    "ExportTitle":"Export lines or pages",
    "全部记录":"all records",
    "数据导出中...":"Export In Progress ..."
  }
})
const props = defineProps({
  url: String,
  pageable: {
    type: Boolean,
    default: false
  },
  pageSize: {
    type: Number,
    default: 10
  },
  method: {
    default: 'post',
    type: String
  },
  lazy: {
    type: Boolean,
    default: false
  },
  transform: {
    type: Function,
    default: (data) => data,
  },
  tools: {
    type: String,
    default: "search,refresh,columns"
  },
  autoPageSize: {
    type: Boolean,
    default: true
  },
  allowExport: {
    type: Boolean,
    default: true
  }
})
const emit = defineEmits(['beforeLoad', 'load', 'afterLoad', 'init'])
const hasSearchSlot = !!slots.search
const hasTop = !!slots.top
const hasBottom = !!slots.bottom
const pageSizes = ref([10, 20, 50, 100])

//let h_table=null

function findHTable(children) {
  for (let i = 0; i < children.length; i++) {
    let child = children[i];
   // console.log(child.type)
    if (child.type && child.type.name == 'HTable') {
      h_table_comp = child
      return child.component.data
    } else if (child.type && child.type.name=='ElTable'){
     // console.log("ElTable",child.component)
      //console.log(child.component.slots.default())
    } else if (child.children instanceof Array) {
      const ret = findHTable(child.children);
      if (ret) {
        return ret;
      }
    }
  }
  return null;
}

function onTableContextMenu(event) {
  let target=event.target
  if(target.tagName=='TD'||target.target=='TR'){
    event.preventDefault()
  }
}

// onUnmounted(() => {
//   if (h_table) {
//     h_table.removeEventListener('contextmenu', onTableContextMenu)
//   }
// })
function findColumns(){
  if (h_table) {
    h_table_columns = h_table.computeColumns.filter(it=>it.prop)
    if (h_table.computeColumns.length > 6) {
      tableRef.value = h_table
    }
  }
}
let current = null
function onInit(dt) {
  emit('init', dt)

  current=getCurrentInstance();
  nextTick(() => {
    setTimeout(() => {
      if (props.autoPageSize) {
        let el=dtRef.value.querySelector('.h-table')||dtRef.value.querySelector('.el-table')
        if (el == null){
          if (!props.lazy) {
            ds.value.load()
          }
          return;
        }
        let clientHeight = el.clientHeight - 50;
        let pageSize = Math.round(clientHeight / 38)
        pageSize = Math.max(5, pageSize)
        pageSizes.value = [pageSize, 20, 50, 100]
        dt.pagination.size = pageSize
        if (!props.lazy) {
          ds.value.load()
        }
      }
    })

    h_table = findHTable(current.subTree.children)
    findColumns()

   // if (h_table) {
    //  watch(h_table.computeColumns,findColumns())
      // h_table_columns = h_table.computeColumns.filter(it=>it.prop)
      // if (h_table.computeColumns.length > 6) {
      //   tableRef.value = h_table
      // }
   // }
  })
}

function pageChange(table, e) {
  table.load()
}

/**============ excel导出 ===============**/
let h_table = null, h_table_comp = null, h_table_columns = [],h_table_instance=null
const exportControl = ref({show: false,exportScope:"selected",exportPages:1,exportColumns:[]})
const exportingInfo = reactive({show:false,percent:0,info:''})
const scopeRadios = ref([{title: '选中行', key: 'selected'}, {title: '当前起第', key: 'page'},{title: t('全部记录'), key: 'all'}])
function showExport() {

 // h_table = findHTable(current.subTree.children)
  findColumns()

  exportControl.value = {
    show: true,
    exportScope:"selected",
    exportPages:1,
    exportColumns:h_table_columns.map(it=>it.prop),
    pageMax:Math.ceil(ds.value.pagination.total/ds.value.pagination.size-ds.value.pagination.page+1)
  }
  if(h_table.checks.length==0){
    scopeRadios.value=[{title: '当前起第', key: 'page'},{title: t('全部记录'), key: 'all'}]
    exportControl.value.exportScope='page'
  }else{
    scopeRadios.value=[{title: '选中行', key: 'selected'}, {title: '当前起第', key: 'page'},{title: t('全部记录'), key: 'all'}]
  }
}
function changeColumnSelect(){
  if(exportControl.value.exportColumns.length>0){
    exportControl.value.exportColumns=[]
  }else{
    exportControl.value.exportColumns=h_table_columns.map(it=>it.prop)
  }
}
//消息确认
function messageConform(msg,title){
  modal({
    title,
    content: msg,
    buttons: [
      {
        type: 'confirm',
        name: t('Confirm'),
        style: 'primary'
      }
    ],
    events: {
      confirm: modal => {
        modal.close();
      }
    }
  })
}
function doExport() {
  let exportOptions=exportControl.value
  let exportTotal=ds.value.pagination.total

  // 根据选项处理导出数据
  if(exportOptions.exportColumns.length==0){
    message($t('','至少需要导出一列数据'))
    return
  }
  exportControl.value={show:false,exportColumns:[]}

  exportingInfo.show=true
  exportingInfo.percent=0
  exportingInfo.info=t('数据导出中...')


  let exportColumns=h_table_columns.filter(it=>exportOptions.exportColumns.indexOf(it.prop)!=-1)

  let temp_index=0
  const processDataRow=async (row)=>{
    let nd={}
    temp_index++
    for(let c of exportColumns){
      if(c.prop=='$index'||c.prop=='$serial'){
        nd[c.prop]=temp_index
        continue
      }
      if(c.prop=='_index'){
        let rIndex=row._index
        if(rIndex==null){
          rIndex=temp_index
        }
        nd[c.prop]=rIndex
        continue
      }

      if(row[c.prop]==null){
        continue
      }
      nd[c.prop]=row[c.prop]
      if(c.format){
        nd[c.prop]=c.format(row[c.prop],true)
      }else if(c.render){
        nd[c.prop]=c.render(row,true)
      }else if(c.dict){
        let dictMapper=await heyuiConfig.getDict(c.dict)
        nd[c.prop]=dictMapper.mapping(row[c.prop])
      }
    }
    return nd
  }



  if(exportOptions.exportScope=='selected'){
    //导出选中行
    let exporter=new ExcelExporter("Excel_"+Date.now(),h_table.checks.length,exportColumns)
    exporter.export(async w=>{
      exportingInfo.percent=100
      for(let item of h_table.checks){
        let d=await processDataRow(item)
        await w(d)
      }
      exportingInfo.info='数据写入中...'
    }).then(r=>{
      messageConform(`文件"${r}"已导出至目标文件夹`)
    }).catch(e=>{
      messageConform(e,'Excel导出错误')
    }).finally(_=>{
      exportingInfo.show=false
    })
  }else if(exportOptions.exportScope=='page'){
    //导出当前往后n页
    //重新分页
    let page=ds.value.pagination.page
    let pageSize=ds.value.pagination.size
    let maxPage=page+exportOptions.exportPages-1
    let realTotal=ds.value.pagination.total
    let totalCount=Math.min(exportOptions.exportPages*pageSize,realTotal-(page-1)*pageSize)
    let exporter=new ExcelExporter("Excel_"+Date.now(),totalCount,exportColumns)

    let getExportData=async (cb)=>{
      let params=Object.assign({},ds.value.params)
      params.pageSize=pageSize
      params.pageNo=page
      let ret = await ajax[props.method](props.url,params)
      let data=ret.data
      for(let item of data){
        let d=await processDataRow(item)
        await cb(d)
      }
    }
    exporter.export(async  w=>{
      while(page<=maxPage){
        exportingInfo.percent=parseInt(page*100/maxPage)
        await getExportData(w)
        page++
      }
      exportingInfo.info='数据写入中...'
    }).then(r=>{
      messageConform(`文件"${r}"已导出至目标文件夹`)
    }).catch(e=>{
      messageConform(e,'Excel导出错误')
    }).finally(_=>{
      exportingInfo.show=false
    })
  }else{
    //导出全部
    let realTotal=ds.value.pagination.total
    let page=1;
    let pageSize=1000
    let maxPage=Math.ceil(ds.value.pagination.total/1000)
    let exporter=new ExcelExporter("Excel_"+Date.now(),realTotal,exportColumns)

    let getExportData=async (cb)=>{
      let params=Object.assign({},ds.value.params)
      params.pageSize=pageSize
      params.pageNo=page
      emit('beforeLoad',params,true)
      let ret = await ajax[props.method](props.url,params)
      let data=ret.data
      emit('load',data,true)
      for(let item of data){
        let d=await processDataRow(item)
        await cb(d)
      }
    }
    exporter.export(async  w=>{
      while(page<=maxPage){
        exportingInfo.percent=parseInt(page*100/maxPage)
        await getExportData(w)
        page++
      }
      exportingInfo.info='数据写入中...'
    }).then(r=>{
      messageConform(`文件"${r}"已导出至目标文件夹`)
    }).catch(e=>{
      messageConform(e,'Excel导出错误')
    }).finally(_=>{
      exportingInfo.show=false
    })
  }
}

/**============ excel导出结束 ===============**/


defineExpose({
  load: () => ds.value.load(),
  getData:()=>toRaw(ds.value.getData()),
  setData: (v) => ds.value.setData(v),
  get params() {
    return ds.value.params
  },
  get pagination() {
    return ds.value.pagination
  },
  get loading() {
    return ds.value.loading
  },
  reload: () => ds.value.reload(),
  setSort: (v) => ds.value.setSort(v)
})
function reset(table){
  util.clean(table.params)
  table.reload()
}
</script>

<template>
  <div class="data-table">
    <div class="data-table-inner">
      <DataSet :url="props.url"
               :pageable="props.pageable"
               :pageSize="props.pageSize"
               :method="props.method"
               :lazy="props.autoPageSize||props.lazy"
               :transform="props.transform"
               @init="onInit"
               @beforeLoad="emit('beforeLoad',$event)"
               @load="emit('load',$event)"
               @afterLoad="emit('afterLoad',$event)"
               ref="ds">
        <template #default="table">
          <!--顶部-->
          <div class="search-bar" v-if="hasTop">
            <div class="search">
              <slot :pagination="table.pagination" :data="table.data" :params="table.params" :load="table.load"
                    :loading="table.loading" :pageChange="table.pageChange" :reload="table.reload"
                    :setSort="table.setSort" name="top"/>
            </div>
          </div>
          <!--搜索条-->
          <div class="search-bar" v-show="showSearch">
            <div class="search">
              <slot :pagination="table.pagination" :data="table.data" :params="table.params" :load="table.load"
                    :loading="table.loading" :pageChange="table.pageChange" :reload="table.reload"
                    :setSort="table.setSort" name="search"/>
            </div>
            <div class="search-btn-group" style="width: 200px" v-if="hasSearchSlot">
              <Button icon="h-icon-search" color="primary" @click="table.reload()">{{t('Search')}}</Button>
              <Button icon="icon-reload" color="gray" @click="reset(table)">{{t('Reset')}}</Button>
            </div>
          </div>
          <!--工具条-->
          <div class="tools">
            <div class="tools-control-group">
              <slot :pagination="table.pagination" :data="table.data" :params="table.params" :load="table.load"
                    :loading="table.loading" :pageChange="table.pageChange" :reload="table.reload"
                    :setSort="table.setSort" name="tools"/>
            </div>
            <div class="tools-grid-group">
              <slot :pagination="table.pagination" :data="table.data" :params="table.params" :load="table.load"
                    :loading="table.loading" :pageChange="table.pageChange" :reload="table.reload"
                    :setSort="table.setSort" name="tool-buttons"/>
              <Button v-if="hasSearchSlot" icon="jeicon-search" title="切换显示" @click="showSearch=!showSearch"
                      icon-circle/>
              <Button v-if="allowExport" icon="jeicon-excel" :title="t('Export')" icon-circle @click="showExport"/>
              <Button icon="jeicon-refresh" :title="t('Refresh')" icon-circle @click="table.load()"/>
              <TableControl v-if="tableRef" :table="tableRef" style="margin-left: 4px;"/>
            </div>
          </div>
          <!--数据页-->
          <div class="data" ref="dtRef">
            <slot :pagination="table.pagination" :data="table.data" :params="table.params" :load="table.load"
                  :loading="table.loading" :pageChange="table.pageChange" :reload="table.reload"
                  :setSort="table.setSort"/>
          </div>
          <!--分页条-->
          <div class="page-bar" v-if="props.pageable">
            <Pagination v-model="table.pagination" @change="table.pageChange($event)" :sizes="pageSizes"
                        align="right"></Pagination>
          </div>
          <div class="page-bar" v-if="hasBottom">
            <slot :pagination="table.pagination" :data="table.data" :params="table.params" :load="table.load"
                  :loading="table.loading" :pageChange="table.pageChange" :reload="table.reload"
                  :setSort="table.setSort" name="bottom"/>
          </div>
        </template>
      </DataSet>
    </div>
    <Modal v-model="exportControl.show" :closeOnMask="false" hasDivider hasCloseIcon>
      <template #header>{{t('DataExport')}}</template>
      <div style="width: 600px">
        <fieldset style="border-radius: 3px">
          <legend style="margin-left: 20px"><strong>{{t('ExportTitle')}}</strong></legend>
          <Radio :datas="scopeRadios" v-model="exportControl.exportScope" style="width: 100%;display: flex;justify-content: space-around;padding-bottom: 10px">
            <template #item="{item}">
                <span v-if="item.key=='page'">
                     {{t('from the current')}} <Input type="number"
                                    v-model="exportControl.exportPages"
                                    min="1"
                                    :max="exportControl.pageMax"
                                    :disabled="exportControl.exportScope!='page'"
                                    class="tb-num-input"
                                    style="width: 60px;appearance: none;"/> {{t('pages')}}
                </span>
              <span v-else>{{ item.title }}</span>
            </template>
          </Radio>
        </fieldset>
        <fieldset style="border-radius: 3px;margin-top: 20px">
          <legend style="margin-left: 20px"><strong>
            <Checkbox :checked="exportControl.exportColumns.length==h_table_columns.length" :indeterminate="exportControl.exportColumns.length>0&&exportControl.exportColumns.length<h_table_columns.length"  @click="changeColumnSelect">{{t('Select All Columns')}}</Checkbox>
          </strong></legend>
          <div style="display: flex;justify-content: space-between;padding:10px;">
            <Checkbox type="object" :datas="h_table_columns" keyName="prop" title="title" v-model="exportControl.exportColumns"></Checkbox>
          </div>
        </fieldset>
      </div>
      <template #footer>
        <Button color="primary" @click="doExport">{{t('Confirm')}}</Button>
      </template>
    </Modal>
    <Modal v-model="exportingInfo.show" :closeOnMask="false" transparent middle>
      <hCircle :percent="exportingInfo.percent" :strokeWidth="24" :size="200" style="background: rgb(243, 243, 243);border-radius: 50%">
        <p style="font-size: 24px">{{exportingInfo.info}}</p>
        <p style="font-size: 18px">{{exportingInfo.percent}}%</p>
      </hCircle>
    </Modal>
  </div>
</template>
